package com.dubbo.rpc.config;

import com.dubbo.rpc.common.ResultCodeEnum;
import com.dubbo.rpc.domain.RpcRequest;
import com.dubbo.rpc.domain.RpcResponse;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Objects;

/**
 * @author liuxin
 * @date 2021/10/10 8:29
 */
public class RpcServerHandler extends SimpleChannelInboundHandler<RpcRequest> {

    private final Map<String, Object> handleMap;

    public RpcServerHandler(Map<String, Object> handleMap) {
        this.handleMap = handleMap;
    }

    @Override
    protected void channelRead0(ChannelHandlerContext channelHandlerContext, RpcRequest rpcRequest) throws Exception {
        System.err.println(4);

        RpcResponse rpcResponse = new RpcResponse();
        rpcResponse.setRequestId(rpcRequest.getRequestId());

        try {
            Object result = handle(rpcRequest);
            rpcResponse.setData(result);
        } catch (Exception e) {
            rpcResponse.setCode(ResultCodeEnum.ERROR.getCode());
            rpcResponse.setMessage(ResultCodeEnum.ERROR.getMessage());
        }

        channelHandlerContext.writeAndFlush(rpcResponse).addListener(ChannelFutureListener.CLOSE);
    }

    /**
     * 核心
     * @param rpcRequest
     * @return
     */
    private Object handle(RpcRequest rpcRequest) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        System.err.println(5);

        String serviceName = rpcRequest.getInterfaceName();
        Object serviceBean = handleMap.get(serviceName);

        if (Objects.isNull(serviceBean)) {
            throw new RuntimeException("can't find service" + serviceName);
        }

        Class<?> serviceCls = serviceBean.getClass();
        String methodName = rpcRequest.getMethodName();
        Class<?>[] paramsTypeArr = rpcRequest.getParamsTypeArr();
        Object[] paramsValArr = rpcRequest.getParamsValArr();

        Method method = serviceCls.getMethod(methodName, paramsTypeArr);
        method.setAccessible(true);
        return method.invoke(serviceBean, paramsValArr);
    }


    @Override
    public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
        System.err.println(cause.getMessage());
        ctx.close();
    }
}
